<template>
  <view class="load-refresh">
    <!-- 刷新动画，可自定义，占高100rpx -->
    <view class="animation" :style="{ '--color': color }">
      <view v-if="!playState" class="remind">
        {{ moving ? '↑ 松开释放' : '↓ 下拉刷新' }}
      </view>
      <view
        v-if="playState && refreshType === 'hollowDots'"
        class="refresh hollow-dots-spinner"
      >
        <view class="dot"></view>
        <view class="dot"></view>
        <view class="dot"></view>
      </view>
      <view
        v-if="playState && refreshType === 'halfCircle'"
        class="refresh half-circle-spinner"
      >
        <view class="circle circle-1"></view>
        <view class="circle circle-2"></view>
      </view>
      <view
        v-if="playState && refreshType === 'swappingSquares'"
        class="refresh swapping-squares-spinner"
      >
        <view class="square"></view>
        <view class="square"></view>
        <view class="square"></view>
        <view class="square"></view>
      </view>
    </view>
    <!-- 数据列表块 -->
    <view
      class="cover-container"
      :style="[
        {
          background: backgroundCover,
          transform: coverTransform,
          transition: coverTransition
        }
      ]"
      @touchstart="coverTouchstart"
      @touchmove="coverTouchmove"
      @touchend="coverTouchend"
    >
      <scroll-view
        scroll-y
        class="list"
        :scroll-top="scrollTop"
        @scrolltolower="loadMore"
        :style="getHeight"
      >
        <!-- 数据集插槽 -->
        <slot name="content-list"></slot>
        <!-- 上拉加载 -->
        <view class="load-more">{{ loadText }}</view>
      </scroll-view>
    </view>
  </view>
</template>

<script>
export default {
  name: 'loadRefresh',
  props: {
    isRefresh: {
      type: Boolean,
      default: true
    },
    refreshType: {
      type: String,
      default: 'hollowDots'
    },
    fixedHeight: {
      type: String,
      default: '0'
    },
    heightReduce: {
      type: String,
      default: '0'
    },
    color: {
      type: String,
      default: '#04C4C4'
    },
    backgroundCover: {
      type: String,
      default: 'white'
    },
    currentPage: {
      type: Number,
      default: 0
    },
    totalPages: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      startY: 0,
      moveY: 0,
      updating: false, // 数据更新状态（true: 更新中）
      updateType: true, // 数据更新类型（true: 下拉刷新: false: 加载更多）
      moving: false,
      scrollTop: -1,
      coverTransform: 'translateY(0px)',
      coverTransition: '0s',
      playState: false // 动画的状态 暂停 paused/开始 running
    }
  },
  computed: {
    // 计算组件所占屏幕高度
    getHeight() {
      // rpx = px / uni.getSystemInfoSync().windowWidth * 750
      if (Number(this.fixedHeight)) {
        return `height: ${this.fixedHeight}rpx;`
      } else {
        let height =
          uni.getSystemInfoSync().windowHeight -
          uni.upx2px(0 + this.heightReduce)
        return `height: ${height}px;`
      }
    },
    // 判断loadText，可以根据需求自定义
    loadText() {
      const { currentPage, totalPages, updating, updateType } = this
      if (!updateType && updating) {
        return '加载中...'
      } else if (currentPage < totalPages) {
        return '上拉加载更多'
      } else {
        return '已经到底啦~'
      }
    }
  },
  methods: {
    // 根据currentPage和totalPages的值来判断 是否触发@loadMore
    loadMore() {
      const { currentPage, totalPages } = this
      if (!this.updating && currentPage < totalPages) {
        this.updating = true
        this.updateType = false
        this.$emit('loadMore')
      }
    },
    // 回弹效果
    coverTouchstart(e) {
      if (!this.isRefresh) {
        return
      }
      this.coverTransition = 'transform .1s linear'
      this.startY = e.touches[0].clientY
    },
    coverTouchmove(e) {
      if (!this.isRefresh || this.updating) {
        return
      }
      this.moveY = e.touches[0].clientY
      let moveDistance = this.moveY - this.startY
      if (moveDistance <= 50) {
        this.coverTransform = `translateY(${moveDistance}px)`
      }
      this.moving = moveDistance >= 50
    },
    coverTouchend() {
      if (!this.isRefresh || this.updating) {
        return
      }
      if (this.moving) {
        this.runRefresh()
      } else {
        this.coverTransition = 'transform 0.3s cubic-bezier(.21,1.93,.53,.64)'
        this.coverTransform = 'translateY(0px)'
      }
    },
    runRefresh() {
      this.scrollTop = 0
      this.coverTransition = 'transform .1s linear'
      this.coverTransform = 'translateY(50px)'
      this.playState = true
      this.updating = true
      this.updateType = true
      this.$emit('refresh')
    },
    completed() {
      if (this.updateType) {
        // 下拉刷新
        this.moving = false
        this.scrollTop = -1
        this.coverTransition = 'transform 0.3s cubic-bezier(.21,1.93,.53,.64)'
        this.coverTransform = 'translateY(0px)'
        setTimeout(() => {
          this.playState = false
        }, 300)
      }
      this.updating = false
    }
  }
}
</script>

<style lang="scss" scoped>
$color: var(--color);

.load-refresh {
  margin: 0;
  padding: 0;
  width: 100%;
  .cover-container {
    width: 100%;
    margin-top: -100rpx;
    .list {
      width: 100%;
      .load-more {
        font-size: 20rpx;
        text-align: center;
        color: #aaaaaa;
        padding: 16rpx;
      }
    }
  }
}

/* 动画 */
.animation {
  width: 100%;
  height: 100rpx;
  .remind {
    width: 100%;
    height: 100rpx;
    text-align: center;
    line-height: 100rpx;
  }
  .refresh {
    width: 100%;
    height: 100rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    view {
      // animation-play-state: $playState!important;
    }
  }

  /* HollowDots  */
  .hollow-dots-spinner .dot {
    width: 30rpx;
    height: 30rpx;
    margin: 0 calc(30rpx / 2);
    border: calc(30rpx / 5) solid $color;
    border-radius: 50%;
    float: left;
    transform: scale(0);
    animation: hollowDots 1000ms ease infinite 0ms;
  }
  .hollow-dots-spinner .dot:nth-child(1) {
    animation-delay: calc(300ms * 1);
  }
  .hollow-dots-spinner .dot:nth-child(2) {
    animation-delay: calc(300ms * 2);
  }
  .hollow-dots-spinner .dot:nth-child(3) {
    animation-delay: calc(300ms * 3);
  }
  @keyframes hollowDots {
    50% {
      transform: scale(1);
      opacity: 1;
    }
    100% {
      opacity: 0;
    }
  }

  /* halfCircle  */
  .half-circle-spinner .circle {
    content: '';
    position: absolute;
    width: 60rpx;
    height: 60rpx;
    border-radius: 100%;
    border: calc(60rpx / 10) solid transparent;
  }

  .half-circle-spinner .circle.circle-1 {
    border-top-color: $color;
    animation: halfCircle 1s infinite;
  }
  .half-circle-spinner .circle.circle-2 {
    border-bottom-color: $color;
    animation: halfCircle 1s infinite alternate;
  }
  @keyframes halfCircle {
    0% {
      transform: rotate(0deg);
    }
    100% {
      transform: rotate(360deg);
    }
  }

  /* swappingSquares */
  .swapping-squares-spinner {
    position: relative;
  }
  .swapping-squares-spinner .square {
    height: calc(65rpx * 0.25 / 1.3);
    width: calc(65rpx * 0.25 / 1.3);
    animation-duration: 1000ms;
    border: calc(65rpx * 0.04 / 1.3) solid $color;
    margin-right: auto;
    margin-left: auto;
    position: absolute;
    animation-iteration-count: infinite;
  }
  .swapping-squares-spinner .square:nth-child(1) {
    animation-name: swappingSquares-child-1;
    animation-delay: 500ms;
  }
  .swapping-squares-spinner .square:nth-child(2) {
    animation-name: swappingSquares-child-2;
    animation-delay: 0ms;
  }
  .swapping-squares-spinner .square:nth-child(3) {
    animation-name: swappingSquares-child-3;
    animation-delay: 500ms;
  }
  .swapping-squares-spinner .square:nth-child(4) {
    animation-name: swappingSquares-child-4;
    animation-delay: 0ms;
  }
  @keyframes swappingSquares-child-1 {
    50% {
      transform: translate(150%, 150%) scale(2, 2);
    }
  }
  @keyframes swappingSquares-child-2 {
    50% {
      transform: translate(-150%, 150%) scale(2, 2);
    }
  }
  @keyframes swappingSquares-child-3 {
    50% {
      transform: translate(-150%, -150%) scale(2, 2);
    }
  }
  @keyframes swappingSquares-child-4 {
    50% {
      transform: translate(150%, -150%) scale(2, 2);
    }
  }
}
</style>
